package study

import (
	"fmt"
	"strconv"
)

// 基本数据类型
// 整型
// 浮点型
// boolean
// 字符串
// 字符: 字符属于 int 类型, 字符有两种类型, byte/uint8 (代表一个 ASCII 码) 和 rune (代表一个 UTF-8 字符, 实际是一个 int32 类型, 需要处理中文, 日文或其他复杂字符时需要使用 rune 类型)
//   Go 使用了特殊的 rune 类型来处理 Unicode, 让基于 Unicode 的文本处理更为方便, 也可以使用 byte 进行默认字符串处理, 性能和拓展性都有照顾
//   修改字符
//   修改字符需要先将其转换成 []rune 或 []byte, 修改完成后子啊转换为 string (无论哪种转换都会重新分配内存, 并复制字节数组)

// ------------------------------ 整型和浮点型的转换 ------------------------------
func Int_Float() {
	var a int8 = 20
	var b int16 = 21
	// fmt.Println(a + b) // mismatched types int8 and int16
	fmt.Println(int16(a) + b)

	var c float32 = 32
	var d float64 = 33
	// fmt.Println(c + d) // mismatched types float32 and float64
	fmt.Println(float64(c) + d)

	e := 32
	f := 33.2
	// fmt.Println(e + f) // mismatched types int and float64
	fmt.Println(float64(e) + f)
}

// ------------------------------ 其他类型和 bool 类型的转换 ------------------------------
func Bool_Others() {
	/** 👇 整型不能和 bool 类型进行转换 👇 */

	/** 👇 string 转 bool (不建议) 👇 */
	// ParseBool returns the boolean value represented by the string.
	// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
	// Any other value returns an error.
	b, _ := strconv.ParseBool("true")
	fmt.Printf("%v", b)
}

// --------------------------------------------------- 字符串常用操作方法 ---------------------------------------------------
func StringFuncs() {
	// len(str): 字符串长度
	// + 和 fmt.Sprintf("%s - %s", str1, str2): 拼接字符串
	// strings.Split(str, sep string): 字符串分割, 返回分割后的切片
	// strings.Join([]string, sep string): join 操作, 把切片连接成字符串
	// strings.Contains(str1, str2): 判断是否包含
	// strings.HasPrefix(str1, str2) & strings.HasSuffix(str1, str2): 前缀/后缀
	// strings.Index(str1, str2) & strings.LastIndex(str1, str2): 字串出现的位置, 查找不到返回 -1
}

// ------------------------------ 改变字符串 ------------------------------
func ChangeString() {
	var a = 'a'           // 通过单引号定义字符
	fmt.Printf("%v\n", a) // 输出: 97 (a 的 ASCII 码值)
	fmt.Printf("%c\n", a) // 输出: a (字符本身)

	s1 := "pig"
	byteS1 := []byte(s1)
	byteS1[0] = 'h'
	fmt.Println(string(byteS1))

	s2 := "哈喽, 123"
	byteS2 := []rune(s2)
	byteS2[0] = 'h'
	fmt.Println(string(byteS2))
}

// --------------------------------------------------- 字符串转基本数据类型 ---------------------------------------------------
func String2BaseDataType() {
	str1 := "true"
	// func ParseBool(str string) (value bool, err error) // 返回两个值
	b, _ := strconv.ParseBool(str1)
	fmt.Printf("b type: %T, b value: %t\n", b, b)

	str2 := "123456"
	/** str: string; base: 进制; bitSize: 0, 8, 16, 32, 64 */
	// func ParseInt(str string, base int, bitSize int) (value int64, err error) // 返回两个值
	i, _ := strconv.ParseInt(str2, 10, 0)
	fmt.Printf("i type: %T, i value: %d\n", i, i)

	str3 := "12.12"
	// func ParseFloat(s string, bitSize int) (float64, error)
	f, _ := strconv.ParseFloat(str3, 64)
	fmt.Printf("f type: %T, f value: %f\n", f, f)

	str4 := "a.12" // 不能转成有效数据时, 会转成对应基本数据的默认值
	a := 10.1
	a, _ = strconv.ParseFloat(str4, 64) // a: 0.000000
	c, _ := strconv.ParseBool(str4)     // c: false
	fmt.Printf("f type: %T, f value: %f\n", a, a)
	fmt.Printf("f type: %T, f value: %t\n", c, c)
}

// --------------------------------------------------- 基本数据类型转字符串 ---------------------------------------------------
func BaseDataType2String() {
	// var i1, f1, b1 int // 声明多个同类型的变量
	var i1, f1, b1 = 10, 10.2, true // 声明多个变量并赋值(可以声明多个不同的变量)
	fmt.Println(i1, f1, b1)

	i := 10
	f := 11.11
	b := true
	c := 'a'
	str := ""

	// 1.通过 fmt.Sprintf 转成 string
	str = fmt.Sprintf("%d", i)
	fmt.Printf("str type: %T, str=%q\n", str, str)
	str = fmt.Sprintf("%f", f)
	fmt.Printf("str type: %T, str=%q\n", str, str)
	str = fmt.Sprintf("%t", b)
	fmt.Printf("str type: %T, str=%q\n", str, str)
	str = fmt.Sprintf("%c", c)
	fmt.Printf("str type: %T, str=%q\n\n", str, str)
	// 2.通过 strconv 包的函数
	// func Itoa(i int) string
	// func FormatInt(i int64, base int) string
	// func FormatUint(i uint64, base int) string
	/** f: 要转的浮点数;
	fmt: 格式;
			'f': -ddd.ddddd;
			'b': -ddddp±ddd(二进制指数);
			'e': -d.dddde±dd(十进制指数);
			'E': -d.ddddE±dd(十进制指数);
			'g': 指数很大时用 'e' 格式, 否则用 'f' 格式
			'G': 指数很大时用 'E' 格式, 否则用 'f' 格式
	prec: 精度控制(排除指数部分);
			对 'f', 'e', 'E' 来说表示保留几位小数
			对 'g', 'G' 来说表示总的数字个数
			prec 为 -1 时, 表示使用最少数量, 但又必须的数字来表示 'f'
	*/
	// func FormatFloat(f float64, fmt byte, prec, bitSize int) string
	// func FormatBool(b bool) string
	str = strconv.Itoa(i)
	fmt.Printf("str type: %T, str=%q\n", str, str)
	str = strconv.FormatInt(int64(i), 10)
	fmt.Printf("str type: %T, str=%q\n", str, str)
	str = strconv.FormatFloat(f, 'f', 10, 64)
	fmt.Printf("str type: %T, str=%q\n", str, str)
	str = strconv.FormatBool(b)
	fmt.Printf("str type: %T, str=%q\n", str, str)
}
